/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.Weighting;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import main.KBProcess.Element;
import main.KBProcess.Fragment;
import main.NER.Trie.NER_Candidate;
import main.NER.Branch;
import main.NER.Stem;
import main.NER.Trie.KBTrie;
import main.Ontology.ElementOntologySet;

import org.apache.commons.math.distribution.NormalDistributionImpl;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.RealMatrix;

/**
 *
 * @author Isaac Osesina
 */
public abstract class AbstractWeightingFunction implements Serializable{


    public List<Fragment> intersectFragments(NER_Candidate candidate) {
        List<Fragment> itersectFrag = new ArrayList<Fragment>(candidate.getStem_LEFT().getFragmentList());
        itersectFrag.retainAll( candidate.getStem_RIGHT().getFragmentList() );
        return itersectFrag;
    }

    public static Set<Element> entitiesIntrinsicProbabilityNotNull(Pattern entityClassRegex,
                                                              List<Fragment> fragmentList,
                                                              double threshold) {
        Set<Element> out = new LinkedHashSet<Element>();
        for(Fragment fragment:fragmentList) {
            if( fragment != null  && fragment.getEntityElement() != null) {
                Element e = fragment.getEntityElement();
                double val = getIntrinsicProbability(e.getValue(), entityClassRegex);
                if( val>0 && val>=threshold) {
                    out.add(e);
                }
            }
        }
        return out;
    }
    

    public static Set<Element> entityTypeSubset_ID(List<Element> masterEntityList,
                                               Set<Element> subEntityList, NER_Candidate candidate) {
        Set<Element> out = new LinkedHashSet<Element>();
        ElementOntologySet branchID = candidate.getOntologies();
        List<Element> tmp = new ArrayList<Element>(masterEntityList);
        tmp.retainAll(subEntityList);
        for(Element entity:tmp) {
            if( entity != null &&
                    entity.getOntologies().equals(branchID)) {
                out.add(entity);
            }
        }
        return out;
    }


    public static double getIntrinsicProbability(String stringVal, Pattern pattern) {
        double max = stringVal.length();
        if(max==0) {
            return 0;
        }
        double min = 0;
        Matcher m = pattern.matcher(stringVal);
        while(m.find() && min<max) {
            double len = m.group().length();
            if(len > min) {
                min = len;
            }
        }        
        return min/max;
    }

    public static double getIntrinsicProbability(String stringVal, Pattern pattern, double threshold) {
        double prob = getIntrinsicProbability(stringVal, pattern);
        prob = prob>=threshold ? prob:0;
        return prob;
    }

    public static double getContextProbability(NER_Candidate candidate, boolean left, double threshold) {
        double prob = 0.0;
        if(candidate != null) {
            Stem stem = null;
            if(left)
                stem = candidate.getStem_LEFT();
            else
                stem = candidate.getStem_RIGHT();
            if(stem != null) {
                ElementOntologySet branchID = candidate.getOntologies();
                Branch child = stem.childByID(branchID);
                if(child != null) {
                    prob = child.getMyTypeProportion();
                    prob = prob >= threshold ? prob:0;
                }
            }
        }
        return prob;
    }

    public static double getProbabilityDensity(NormalDistributionImpl distribution, double val, double lowerBoundZ) {
        double z = (val - distribution.getMean())/distribution.getStandardDeviation();
        if(z<=lowerBoundZ) {
            return distribution.density(val);
        }
        return 0;
    }

    


    public static NormalDistribution getNormalDistribution(List<Double> list) {
        Double array[] = list.toArray(new Double[list.size()]);
        return getNormalDistribution(array);
    }

    public static NormalDistribution getNormalDistribution(Double array[]) {
        double array2[] = new double[array.length];
        for(int i=0; i<array.length; i++) {
            double d = array[i];
            array2[i] = d;
        }
        return getNormalDistribution(array2);
    }

    public static NormalDistribution getNormalDistribution(double array[]) {
        if(array == null || array.length==0) {
            return null;
        }
        int maxIdx = 0; double max = array[0];
        int minIdx = 0; double min = array[0];
        double sumX = array[0];
        for (int i = 1; i < array.length; i++) {
                sumX += array[i];
                if( max<array[i] ) {
                    max = array[i];
                    maxIdx = i;
                }
                if( min>array[i] ) {
                    min = array[i];
                    minIdx = i;
                }
        }
        double mean = sumX / array.length;
        double sumX2 = 0;
        for (int i = 0; i < array.length; i++) {
                sumX2 += Math.pow(array[i] - mean, 2);
        }
        double variance =  sumX2 / array.length ;
        double sd = Math.sqrt(variance);
        if(sd<=0.0) {
            sd = Double.MIN_VALUE;
        }
        NormalDistribution normDist = new NormalDistribution(mean, sd);
        normDist.setArray(array);
        normDist.setMaxIdx(maxIdx);
        normDist.setMinIdx(minIdx);
        return normDist;
    }

    public static NormalDistribution getNormalDistribution(double array1[], double array2[]) {
        RealMatrix m = new Array2DRowRealMatrix(array1);
        RealMatrix n = new Array2DRowRealMatrix(array2);
        RealMatrix cov = m.multiply(n.transpose());
        int rowDim = cov.getRowDimension();
        int colDim = cov.getColumnDimension();
        double array[] = new double[rowDim*colDim];
        for(int col=0; col<colDim; col++) {
            for(int row=0; row<rowDim; row++) {
                array[row+(col*rowDim)] = cov.getEntry(row, col);
            }
        }
        return getNormalDistribution(array);
    }


    public static NormalDistribution getNormalDistribution(NormalDistribution normDist1, NormalDistribution normDist2) {
        NormalDistribution normalDistribution = getNormalDistribution(normDist1.getArray(), normDist2.getArray());
        List<String> parameterValues = new LinkedList<String>(normDist1.getParameters());
        parameterValues.addAll(normDist2.getParameters());
        normalDistribution.setParameters(parameterValues);
        return normalDistribution;
    }



//    public static LinkedHashSet<Integer> subSetEntityValueExactMatch(Pattern entityClassRegex, ArrayList<Element> entityList,
//                                               LinkedHashSet<Integer> entityIDList) {
//        LinkedHashSet<Integer> out = new LinkedHashSet<Integer>();
//        for(Element entity:entityList) {
//            if( entityIDList.contains( entity.getId() ) ) {
//                if( isExactMatchEntityValue(entityClassRegex, entity.getValue()) ) {
//                    out.add(entity.getId());
//                }
//            }
//        }
//        return out;
//    }

//    public static LinkedHashSet<Integer> subSetEntityValueExactMatch(Pattern entityClassRegex, LinkedHashSet<Element> entityList,
//                                               LinkedHashSet<Integer> entityIDList) {
//        LinkedHashSet<Integer> out = new LinkedHashSet<Integer>();
//        for(Element entity:entityList) {
//            if( entityIDList.contains( entity.getId() ) ) {
//                if( isExactMatchEntityValue(entityClassRegex, entity.getValue()) ) {
//                    out.add(entity.getId());
//                }
//            }
//        }
//        return out;
//    }

    public static boolean isMatchEntityValue(Pattern entityClassRegex, String val) {
        Matcher m = entityClassRegex.matcher(val);
        if(m.find()) {
            return true;
        }
        return false;
    }

    public static boolean isExactMatchEntityValue(Pattern entityClassRegex, String val) {
        int max = val.length();
        int len = 0;
        Matcher m = entityClassRegex.matcher(val);
        while(m.find()&& len<max) {
            len = m.group().length();
            if(len>=max) {
                return true;
            }
        }
        return false;
    }
    
}
